'****************************************************************
'*  Name    : Inverter.BAS                                      *
'*  Author  : Sougata Das                                       *
'*  Notice  : Copyright (c) 2005 The Andig Technologies         *
'*          : All Rights Reserved                               *
'*  Date    : 30-07-2005                                        *
'*  Version : 1.0                                               *
'*  Notes   : Uses a PIC18F452. Outputs MOSFET DRIVE THROUGH    *                
'*          ' HWPM + CD4081 FOR CHANNEL CONTROL.                *
'*          ' LOOKUP TABLE FOR SINE                             *
'*          ' INTERRUPT FOR 1)CURRENT LIMIT,2)MOS-DRIVE,3) UPS MODE
'*          :                                                   *
'****************************************************************
                                  '
    DEFINE OSC 40                 'USES A 10MHz CRYSTAL IN x4 PLL MODE FOR 40MHz CLOCK
    DEFINE USE_LFSR 1             'Makes some code shorter
'*******************************************************************************
' Define interrupt handler        '
    DEFINE INTHAND myint          '
                                  '
'********* LCD PORT DEFINITIONS ************************************************

    DEFINE LCD_DREG PORTD         ' Set LCD Data port PORTD
    DEFINE LCD_DBIT 0             ' Set starting Data bit (0 or 4) if 4-bit bus i.e, PortD.0-PORTD.3
    DEFINE LCD_RSREG PORTC        ' Set LCD Register Select PORTC
    DEFINE LCD_RSBIT 5            ' Set LCD Register Select bit i.e, PORTC.5
    DEFINE LCD_EREG PORTC         ' Set LCD Enable port
    DEFINE LCD_EBIT 4             ' Set LCD Enable bit i.e, PORTC.4
    DEFINE LCD_BITS 4             ' Set LCD bus size to 8 bits
    DEFINE LCD_LINES 2            ' Set number of lines on LCD to 4 Lines
    DEFINE LCD_COMMANDUS 2000     ' Set command delay time in us
    DEFINE LCD_DATAUS 50          ' Set data delay time in us
    
'Variables for saving state in interrupt handler *******************************
wsave	        VAR	BYTE bankA system	' Saves W
ssave	        VAR	BYTE bankA system	' Saves STATUS
fsave	        VAR	WORD bankA system	' Saves FSR0
'///////////////////////////////////////////////////////////////////////////////
DEAD            VAR BIT  bankA system   ' SET FOR DEAD TIME SETTING CLEARED EVERY ZERO-CROSS
TIM0INT         VAR BIT  bankA system   ' TIMER0 INTERRUPT CLEARED WHEN IT OCCURS
SYNCOK          VAR BIT  bankA system   ' SET WHEN SYNCHRONIZED TO MAIN
AC              VAR BIT  bankA system   ' SET WHEN AC IS AVAILABLE
PHASE           VAR BIT  bankA system   ' DRIVE PHASE (DETERMINE WHICH CYCLE)
OVERCURRENT     VAR BIT  bankA system   ' SET WHEN AN OVERLOAD INTERRUPT OCCURS
ADCINT          VAR BIT  bankA system   ' SET WHEN AD CONVERSION HAS FINISHED (RESET AT INT)
INTVAL          VAR WORD bankA system   ' PWM UPDATE INTERRUPT (ADJUSTED TO LOCK TO AC)
INDEX           VAR BYTE bankA system   ' SINE-TABLE INDEX POINTER
PWMVAL          VAR BYTE bankA system   ' PWMVALUE FOR FIRING
TEMP            VAR WORD                ' TEMPORARY VARIABLE

    MOS1        VAR PORTC.0             ' MOSFET CHANNEL-1 GATE DRIVE
    MOS2        VAR PORTC.1             ' MOSFET CHANNEL-2 GATE DRIVE
    PULSE       VAR PORTC.2             ' MODULATING PWM OUTPUT (32KHz, SINE-TABLED)
    LCDLAMP     VAR PORTC.3             ' CONTROLS THE LCD BACKLIGHT - 0=ON,1=OFF
    RELAY       VAR PORTD.4             ' TRANSFER RELAY + INDICATION
    BUZZER      VAR PORTD.5             ' AUDIO ANNUNCIATION
    FAULT       VAR PORTD.6             ' FAULT INDICATION
    LOCKED      VAR PORTD.7             ' SYNC-LOCK TO AC INDICATION
    
    OVERLOAD    VAR PORTB.0             ' MOSFET OVERLAOD INPUT / IMMEDIATE SHUTDOWN
    FAIL        VAR PORTB.1             ' AC-FAIL INPUT (FROM16F676)
    SYNC        VAR PORTB.2             ' AC-MAINS SYNC INPUT
    STANDBY     VAR PORTB.3             ' STANDBY/OFF SWITCH (INVERTER-MODE)
    TRICKLE     VAR PORTB.4             ' SWITCHES-OFF THE BATTERY CHARGER
    MENU        VAR PORTB.5             ' MENU-BUTTON
    INCR        VAR PORTB.6             ' INCREASE-BUTTON
    DECR        VAR PORTB.7             ' DECREASE-BUTTON
    
    TP1         VAR PORTE.0             ' TEST POINT 1 FOR OSCILLOSCOPE CHECK
    TP2         VAR PORTE.1             ' TEST POINT 2 FOR OSCILLOSCOPE CHECK
    HEARTBEAT   VAR PORTE.2             ' HEART-BEAT LED
      
'******PORT DATA DIRECTIONS ****************************************************
    LATC     = 0                        ' CLEAR THE PORTC DATA LATCHES
    TRISC    = %10000000                ' SET PORTC DIRECTIONS
    PORTC    = 0                        ' MAKE-SURE THAT THE MOSFETS ARE TURNED-OFF
    TRISA    = %00111111
    
    
    TRISD    = %00000000                ' PORTD DATA DIRECTIONS (ALL OUTPUTS)
    PORTD    = 0                        ' TURN-ON BACKLIGHT AND OTHERS OFF
    TRISB    = %11101111                ' SET PORTB DIRECTIONS
    PORTB.4  = 0                        ' TURN-OFF CHARGER
    TRISE    = %00000000                ' PORTE DATA DIRECTIONS (ALL-OUTPUTS)
    PORTB    = 0                        ' TURN-OFF HEARTBEAT AND TEST POINTS
    ADCON0   = %10000000                ' RIGHT JUSTIFY,FOSC/64
    ADCON1   = %11000010                ' FOSC/64, PORTE DIGITAL

'*******************************************************************************

GOTO STARTUP ' SKIP AROUND THE INTERRUPT HANDLER    
    
' ***Assembly language INTERRUPT handler****************************************
Asm
myint

; Save the state of critical registers
		movwf	wsave			   ; Save W
		swapf	STATUS, W		   ; Swap STATUS to W (swap avoids changing STATUS)
		clrf	STATUS			   ; Clear STATUS
		movwf	ssave			   ; Save swapped STATUS

; Save the FSR value because it gets changed below	
		movf	Low FSR0, W		   ; Move FSR0 lowbyte to W
		movwf	fsave			   ; Save FSR0 lowbyte
		movf	High FSR0, W	   ; Move FSR0 highbyte to W
		movwf	fsave+1			   ; Save FSR0 highbyte
; CHECK IF OVERLOAD OCCURED i,e., PORTB.0 INTERUPTED (FIRST PRIORITY)
        btfss   INTCON, INT0IF     ; CHECK IF OVERLOAD OCCURED
        GoTo    CHECKAC
; TURN-OFF THE GATE DRIVES (PORTC.0&PORTC.1) RETAINING OTHER BITS (PULSE BY PULSE LIMIT)
        MOVLW   0xFC               ; MOVE '11111100
        ANDWF   PORTC,1            ; ADD W WITH PORTC AND PLACE IN PORTC
        bcf     INTCON, INT0IF     ; CLEAR THE HARDWARE INTERRUPT FLAG PORTB.0
        bsf     OVERCURRENT        ; SET THE SOFTWARE OVERLOAD FLAG
; CHECK IF THE AC-FAILED i,e., IF PORTB.1 INTERRUPTED  
CHECKAC
        btfss   INTCON3, INT1IF    ; CHECK IF AC-FAILED OCCURED
        GoTo    AC_SYNC            ; IF AC DID NOT FAILED THEN SKIP AND CHECK FOR TIMER0
        bsf     PORTD, 4           ; TURN-ON THE TRANSFER RELAY
        bcf     INTCON3, INT1IF    ; CLEAR THE AC-FAIL INTERRUPT FLAG
        bcf     AC                 ; CLEAR THE AC FLAG
        bcf     SYNCOK             ; CLEAR THE SYNCHRONIZED FLAG        
        bcf     INTCON3, INT1IE    ; DISABLE FURTHER AC-CHECK INTERRUPTS
        bcf     INTCON3, INT2IE    ; DISABLE FURTHER SYNC INTERRUPT

; SYNCHRONIZE THE AC-FREE RUNNING TIMER
AC_SYNC        
        btfss   INTCON3, INT2IF    ; CHECK IF AC-FAILED OCCURED
        GoTo    TIMEKEEP           ; IF AC-SYNC DID NOT OCCUR THEN SKIP AND CHECK FOR TIMER0
        bcf     INTCON3, INT2IF    ; CLEAR THE INT2 HARDWARE FLAG
        MOVLW   0x0                ; MOVE ZERO TO THE WORKING REGISTER
        MOVWF   TMR1H              ; RESET TMR1H
        MOVWF   TMR1L              ; RESET TMR1L
; CHECK FOR TIMER0 INTERRUPT EVERY 312.5uS 		
TIMEKEEP

        btfss   INTCON, TMR0IF     ; TEST IF T0 OVERFLOWED
        GoTo    FINISHED           ; SKIP IF SET
        BTG     PORTC, 3           ; TOGGLE THE LCDLAMP FOR SCOPE CHECK
        MOVLW   0xFC               ; MOVE '11111100
        ANDWF   PORTC,1            ; ADD W WITH PORTC AND PLACE IN PORTC
        movff   INTVAL+1,TMR0H     ; MOVE THE HIGH VALUE TO W REG 
        movff   INTVAL,  TMR0L     ; MOVE THE LOW VALUE TO W REG 
        bcf     TIM0INT            ; CLEAR THE TIM0INT SOFTWARE FLAG
        bcf     INTCON, TMR0IF     ; CLEAR THE TIMER0 INT HARDWARE FLAG
        bcf     ADCINT             ; CLEAR THE ADC INTERRUPT FLAG
        incf    INDEX, 1           ; INCREMENT INDEX
        movf    INDEX, W           ;
        sublw   .32                ; Substract INDEX FROM 32
        btfss	STATUS,Z
        GoTo    FINISHED           ; SKIP PHASE CHANGE (INDEX RESET)
        clrf    INDEX              ; CLEAR THE INDEX
        btg     PHASE              ; TOGGLE THE PHASE
; Restore FSR, PCLATH, STATUS and W registers
FINISHED 
		movf	fsave, W		   ; retrieve FSR0 lowbyte value
		movwf	Low FSR0		   ; Restore it to FSR0 lowbyte
		movf	fsave+1, W		   ; retrieve FSR0 highbyte value
		movwf	High FSR0		   ; Restore it to FSR0 highbyte
		swapf	ssave, W		   ; Retrieve the swapped STATUS value (swap to avoid changing STATUS)
		movwf	STATUS			   ; Restore it to STATUS
		swapf	wsave,  F		   ; Swap the stored W value
		swapf	wsave,  W		   ; Restore it to W (swap to avoid changing STATUS)
        retfie					   ; Return from the interrupt
EndAsm
'///////////////////////////////////////////////////////////////////////////////    

'///////////////////////////////////////////////////////////////////////////////

    
STARTUP:
LCDOUT $FE, 1 :PAUSE 100          ' CLEAR AND INITIALIZE THE LCD
LCDOUT "ANDIG INVERTER"           ' DISPLAY MESSAGE


'***PWM SETUP //////////////////////////////////////////////////////////////////    
    PR2     = $FF          ' SET THE PWM PERIOD TO 255}
    T2CON   = %00000100    ' PRESCALE=1, TIMER2 0N    } YIELDS A 39KHz PWM
    CCPR1L  = 0            ' SET THE DUTY CYCLE INITIALLY TO 0
    CCP1CON = %00001100    ' CONFIGURE AND START AS PWM
'***END OF PWM SETUP ///////////////////////////////////////////////////////////

'* TIMER ZERO SETUP/////////////////////////////////////////////////////////////
T0CON  = %00001000         ' NO-PRESCALE , 16BIT, OFF AT THIS MOMENT
TMR0H = $FF                ' LOAD THE HIGH BYTE
TMR0L = $CA                ' LOAD THE LOW BYTE
'* END OF TIMER ZERO SETUP//////////////////////////////////////////////////////

'** SET UP THE INTERRUPTS///////////////////////////////////////////////////////
INTCON  = %00110000 ' TMR0 = 1, INT0 = 1 , PIE = 0, GIE=0 AT THIS MOMENT,
INTCON2 = %00000000 ' PULLUP = 1,OVERLOAD=AC-FAIL=SYNC=FALLING EDGE
INTCON3 = %00000000 '%00011000 ' INT1=INT2=1, LOW PRIORITY (NOW NOT ENABLED)
'** END OF SET UP OF THE INTERRUPTS/////////////////////////////////////////////

'** SET UP TIMER1 FOR AC-SYCN COUNTING (FREE-RUNNING) 
                     ' THIS VALUE IS ADJUSTED ONLY DURING SYNCHRONIZE PHASE
INTCON.7 = 1         ' ENABLE GLOBAL INTERRUPT
T0CON.7  = 1         ' START TIMER 0


FIRE:
TEMP = TMR0L                    ' NEEDED FOR THE SIMULATOR TO UPDATE TMR0H 
IF TIM0INT = 0 THEN             ' IF A FRESH FIRING IS NEEDED THEN
   TIM0INT = 1                  ' SET THE SOFTWARE INT FIRING FLAG
    
    LOOKUP INDEX, [0,25,50,74,98,120,142,162,180,197,212,_ ' GET THE PWMVALUE
    225,235,244,250,254,255,254,250,244,235,_
    225,212,197,180,162,142,120,98,74,50,25],PWMVAL
    
    CCPR1L = PWMVAL             ' LOAD THE PWMVAL TO THE HWPWM
         IF PHASE = 0 THEN      ' FIRE THE MOSFETS ACCORDING TO THE PHASE VALUE
             MOS1 = TIM0INT     ' FIRE USING SAFETY LOGIC
             ELSE               ' EITHER CHANNEL 1 OR CHANNEL 2 (DEPENDS ON PHASE)
             MOS2 = TIM0INT     ' FIRING USING SAFETY LOGIC
         ENDIF

ENDIF
GOTO FIRE

              
